#include "tcpci_event.h"
#include "tcpci_timer.h"
#include "pd_policy_engine.h"
#include "pd_core.h"
#include "tcpm.h"
#include "pd_dpm_core.h"
#include "tcpci.h"
#include "tcpci_core.h"

#undef LOG_TAG
#define LOG_TAG    "tcpc_event"
#include "elog.h"

static inline void pd_postpone_vdm_event(struct sgm41620_tcpc *tcpc)
{
	/*
	 * Postpone VDM retry event due to the retry reason
	 * maybe interrupt by some PD event ....
	 */

	struct pd_event *vdm_event = &tcpc->pd_vdm_event;

	if (tcpc->pd_pending_vdm_event && vdm_event->pd_msg) {
		tcpc->pd_postpone_vdm_timeout = false;
		//log_i("pd_postpone_vdm_event 1111111\r\n");	
		tcpc_restart_timer(tcpc, PD_PE_VDM_POSTPONE);
	}
}

void pd_postpone_vdm_event_timeout(struct sgm41620_tcpc *tcpc_dev)
{
	struct pd_event *vdm_event = &tcpc_dev->pd_vdm_event;

	if (tcpc_dev->pd_pending_vdm_event && vdm_event->pd_msg) {
		tcpc_dev->pd_postpone_vdm_timeout = true;
		//log_i("pd_postpone_vdm_timeout = true\r\n");
		tcpc_event_thread_wake_up(tcpc_dev);
	}
}

 void __pd_free_msg(struct sgm41620_tcpc *tcpc_dev, struct pd_msg *pd_msg)
{
	int index = pd_msg - tcpc_dev->pd_msg_buffer;
	uint8_t mask = 1 << index;
	
	tcpc_dev->pd_msg_buffer_allocated &= (~mask);
}

void __pd_free_event(struct sgm41620_tcpc *tcpc_dev, struct pd_event *pd_event)
{
	if (pd_event->pd_msg) {
		__pd_free_msg(tcpc_dev, pd_event->pd_msg);
		pd_event->pd_msg = NULL;
	}
}

bool pd_is_msg_empty(struct sgm41620_tcpc *tcpc_dev)
{
    bool empty;

    empty = !tcpc_dev->pd_msg_buffer_allocated;
    return empty;
}

struct pd_msg *__pd_alloc_msg(struct sgm41620_tcpc *tcpc_dev)
{
	int i;
	uint8_t mask;

	for (i = 0, mask = 1; i < PD_MSG_BUF_SIZE; i++, mask <<= 1) {
		if ((mask & tcpc_dev->pd_msg_buffer_allocated) == 0) {
			tcpc_dev->pd_msg_buffer_allocated |= mask;
			return tcpc_dev->pd_msg_buffer + i;
		}
	}

	log_i("__pd_alloc_msg failed\r\n");	

	return (struct pd_msg *)NULL;
}

static inline void pd_discard_pending_vdm_event(struct sgm41620_tcpc *tcpc)
{
    if (tcpc->pd_pending_vdm_event) {
        __pd_free_event(tcpc, &tcpc->pd_vdm_event);
        tcpc->pd_pending_vdm_event = false;
        tcpc->pd_pending_vdm_reset = false;
        tcpc_disable_timer(tcpc, PD_PE_VDM_POSTPONE);
    }
}

bool pd_put_event(struct sgm41620_tcpc *tcpc_dev,const struct pd_event *pd_event, 
                  bool from_port_partner)
{
    int index = 0;

    if (from_port_partner)
        pd_discard_pending_vdm_event(p_tcpc_dev);

    if (tcpc_dev->pd_event_count >= PD_EVENT_BUF_SIZE) {
        log_e("pd_put_event failed\r\n");
        return false;
    }

    index = (tcpc_dev->pd_event_head_index + tcpc_dev->pd_event_count);
    index %= PD_EVENT_BUF_SIZE;

    tcpc_dev->pd_event_count++;
    tcpc_dev->pd_event_ring_buffer[index] = *pd_event;

    tcpc_event_thread_wake_up(tcpc_dev);
    return true;
}

bool pd_put_pe_event(struct pd_port *pd_port, uint8_t pe_event)
{
	struct pd_event evt = {
		.event_type = PD_EVT_PE_MSG,
		.msg = pe_event,
		.pd_msg = NULL,
	};

	return pd_put_event(p_tcpc_dev, &evt, false);
}

bool pd_put_dpm_notify_event(struct pd_port *pd_port, uint8_t notify)
{
	struct pd_event evt = {
		.event_type = PD_EVT_DPM_MSG,
		.msg = PD_DPM_NOTIFIED,
		.msg_sec = notify,
		.pd_msg = NULL,
	};

	return pd_put_event(p_tcpc_dev, &evt, false);
}

bool pd_put_dpm_ack_event(struct pd_port *pd_port)
{
	struct pd_event evt = {
		.event_type = PD_EVT_DPM_MSG,
		.msg = PD_DPM_ACK,
		.pd_msg = NULL,
	};

	return pd_put_event(p_tcpc_dev, &evt, false);
}

bool pd_put_dpm_nak_event(struct pd_port *pd_port, uint8_t notify)
{
	struct pd_event evt = {
		.event_type = PD_EVT_DPM_MSG,
		.msg = PD_DPM_NAK,
		.msg_sec = notify,
		.pd_msg = NULL,
	};

	return pd_put_event(p_tcpc_dev, &evt, false);
}

bool pd_put_tcp_pd_event(struct pd_port *pd_port, uint8_t event, uint8_t from)
{
	struct pd_event evt = {
		.event_type = PD_EVT_TCP_MSG,
		.msg = event,
		.msg_sec = from,
		.pd_msg = NULL,
	};

	return pd_put_event(p_tcpc_dev, &evt, false);
};

bool pd_put_dpm_event(struct pd_port *pd_port, uint8_t msg)
{
	struct pd_event evt = {
		.event_type = PD_EVT_DPM_MSG,
		.msg = msg,
		.pd_msg = NULL,
	};

	return pd_put_event(p_tcpc_dev, &evt, false);
}

bool pd_put_tcp_vdm_event(struct pd_port *pd_port, uint8_t event)
{
	struct pd_event evt = {
		.event_type = PD_EVT_TCP_MSG,
		.msg = event,
		.msg_sec = PD_TCP_FROM_PE,
		.pd_msg = NULL,
	};
	return pd_put_vdm_event(p_tcpc_dev, &evt, false);
};

#if CONFIG_USB_PD_REV30
bool pd_put_sink_tx_event(struct sgm41620_tcpc *tcpc, uint8_t cc_res)
{
	struct pd_event evt = {
		.event_type = PD_EVT_HW_MSG,
		.msg = PD_HW_SINK_TX_CHANGE,
		.pd_msg = NULL,
	};

	evt.msg_sec = cc_res == TYPEC_CC_VOLT_SNK_3_0;
	return pd_put_event(tcpc, &evt, false);
}
#endif	/* CONFIG_USB_PD_REV30 */

#if 0
static bool __pd_get_event(
	struct sgm41620_tcpc *tcpc_dev, struct pd_event *pd_event)
{
	int index = 0;

	/*if (tcpc_dev->pd_event_count <= 0)
		return false;

	log_i(": %s: before pd_event_count = %d,i\r\n",__func__,tcpc_dev->pd_event_count);
	tcpc_dev->pd_event_count--;

	*pd_event =
		tcpc_dev->pd_event_ring_buffer[tcpc_dev->pd_event_head_index];

	if (tcpc_dev->pd_event_count) {
		index = tcpc_dev->pd_event_head_index + 1;
		index %= PD_EVENT_BUF_SIZE;
	}
	tcpc_dev->pd_event_head_index = index;
	log_i(": %s pd_event_count = %d,index=%d!!\r\n",__func__,tcpc_dev->pd_event_count,index);*/
	return true;
}
#endif

bool pd_get_event(struct sgm41620_tcpc *tcpc_dev, struct pd_event *pd_event)
{

	int index = 0;

	if (tcpc_dev->pd_event_count <= 0)
		return false;

	//log_i(": before pd_event_count = %d,i\r\n",tcpc_dev->pd_event_count);
	tcpc_dev->pd_event_count--;

	*pd_event =
		tcpc_dev->pd_event_ring_buffer[tcpc_dev->pd_event_head_index];

	if (tcpc_dev->pd_event_count) {
		index = tcpc_dev->pd_event_head_index + 1;
		index %= PD_EVENT_BUF_SIZE;
	}
	tcpc_dev->pd_event_head_index = index;
	//log_i(": %s pd_event_count = %d,index=%d!!\r\n",__func__,tcpc_dev->pd_event_count,index);
	return true;
	
	//ret = __pd_get_event(tcpc_dev, pd_event);
	
}

static inline bool pd_check_vdm_state_ready(struct pd_port *pd_port)
{
	switch (pd_port->pe_vdm_state) {
	case PE_SNK_READY:
	case PE_SRC_READY:

#if CONFIG_USB_PD_CUSTOM_DBGACC
	case PE_DBG_READY:
#endif	/* CONFIG_USB_PD_CUSTOM_DBGACC */
		return true;

	default:
		return false;
	}
}

static inline bool pd_get_attention_event(
	struct sgm41620_tcpc *tcpc_dev, struct pd_event *pd_event)
{
	struct pd_event attention_evt = {
		.event_type = PD_EVT_PD_MSG,
		.msg = PD_DATA_VENDOR_DEF,
		.pd_msg = NULL,
	};

	*pd_event = attention_evt;
	pd_event->pd_msg = __pd_alloc_msg(tcpc_dev);

	if (pd_event->pd_msg == NULL)
		return false;

	tcpc_dev->pd_pending_vdm_attention = false;
	*pd_event->pd_msg = tcpc_dev->pd_attention_vdm_msg;
	return true;
}

bool pd_get_vdm_event(struct sgm41620_tcpc *tcpc_dev, struct pd_event *pd_event)
{
    struct pd_event crc_evt = {
        .event_type = PD_EVT_CTRL_MSG,
        .msg = PD_CTRL_GOOD_CRC,
        .pd_msg = NULL,
    };

    struct pd_event reset_evt = {
        .event_type = PD_EVT_PE_MSG,
        .msg = PD_PE_VDM_RESET,
        .pd_msg = NULL,
    };

    struct pd_event *vdm_event = &tcpc_dev->pd_vdm_event;
    bool ret = false;

    if (tcpc_dev->pd_pending_vdm_good_crc) {
        // there is no need to handle good_crc event
        *pd_event = crc_evt;
        tcpc_dev->pd_pending_vdm_good_crc = false;
        ret = true;
        goto out;
    }

    if (tcpc_dev->pd_pending_vdm_event) {
        if (vdm_event->pd_msg && !tcpc_dev->pd_postpone_vdm_timeout) {
            // vdm from port_partner need be postponed
            goto out;
        }

        if (tcpc_dev->pd_pending_vdm_reset) {
            // vdm reset event from port_partner
            *pd_event = reset_evt;
            tcpc_dev->pd_pending_vdm_reset = false;
        } else {
            *pd_event = *vdm_event;
            tcpc_dev->pd_pending_vdm_event = false;
        }
        ret = true;
        goto out;
    }

    if (tcpc_dev->pd_pending_vdm_attention && pd_check_vdm_state_ready(p_pd_port)) {
        ret = pd_get_attention_event(tcpc_dev, pd_event);
        goto out;
    }

out:
    return ret;
}

static inline bool __pd_put_hw_event(struct sgm41620_tcpc *tcpc_dev, uint8_t hw_event)
{
	struct pd_event evt = {
		.event_type = PD_EVT_HW_MSG,
		.msg = hw_event,
		.pd_msg = NULL,
	};
	//log_i("fuc: %s\r\n",__func__);
	return pd_put_event(tcpc_dev, &evt, false);
}

static inline bool  __pd_put_pe_event(struct sgm41620_tcpc *tcpc_dev, uint8_t pe_event)
{
	struct pd_event evt = {
		.event_type = PD_EVT_PE_MSG,
		.msg = pe_event,
		.pd_msg = NULL,
	};
	//log_i("fuc: %s:\r\n",__func__);
	return pd_put_event(tcpc_dev, &evt, false);
}

static inline bool pd_reset_pe_vdm_state(struct sgm41620_tcpc *tcpc, uint32_t vdm_hdr)
{
	bool vdm_reset = false;

	//log_i("pd_reset_pe_vdm_state :vdm_hdr = %x\r\n",vdm_hdr);
	if (PD_VDO_SVDM(vdm_hdr)) {
		if (PD_VDO_CMDT(vdm_hdr) == CMDT_INIT)
			vdm_reset = true;
	} else {
		if (p_pd_port->data_role == PD_ROLE_UFP){
			log_i("pd_reset_pe_vdm_state :vdm_reset = true\r\n");
			vdm_reset = true;
		}
	}

	if (vdm_reset)
		tcpc->pd_pending_vdm_reset = true;

	return vdm_reset;
}


static inline bool pd_is_init_attention_event(
	struct sgm41620_tcpc *tcpc_dev, struct pd_event *pd_event)
{
	uint32_t vdm_hdr = pd_event->pd_msg->payload[0];

	if (!PD_VDO_SVDM(vdm_hdr))
		return false;

	if ((PD_VDO_CMDT(vdm_hdr) == CMDT_INIT) &&
			PD_VDO_CMD(vdm_hdr) == CMD_ATTENTION) {
		return true;
	}

	return false;
}


//__pd_put_event repalce by pd_put_event
bool real_pd_put_cc_attached_event(
		struct sgm41620_tcpc *tcpc, uint8_t type)
{
	struct pd_event evt = {
		.event_type = PD_EVT_HW_MSG,
		.msg = PD_HW_CC_ATTACHED,
		.msg_sec = type,
		.pd_msg = NULL,
	};

	switch (type) {
	case TYPEC_ATTACHED_SNK:
	case TYPEC_ATTACHED_SRC:
	case TYPEC_ATTACHED_DBGACC_SNK:
		//log_i("tcpc->pd_pe_running = true!\r\n");
		tcpc->pd_pe_running = true;
		tcpc->pd_wait_pe_idle = false;
		break;
	default:
		break;
	}
	//log_i("%s\r\n",__func__);
	return pd_put_event(tcpc, &evt, false);
	//return __pd_put_event(tcpc, &evt, false);
}

bool pd_put_cc_attached_event(
		struct sgm41620_tcpc *tcpc, uint8_t type)
{
	bool ret = false;
	//log_i("[wang:]pd_put_cc_attached_event11!!\r\n");
#if 0
	int rv = 0;
	union power_supply_propval val = {.intval = 0};
#endif /* CONFIG_USB_PD_WAIT_BC12 */


#if 0
	rv = power_supply_get_property(tcpc->chg_psy,
		POWER_SUPPLY_PROP_USB_TYPE, &val);
	if ((type == TYPEC_ATTACHED_SNK || type == TYPEC_ATTACHED_DBGACC_SNK) &&
		(rv < 0 || val.intval == POWER_SUPPLY_USB_TYPE_UNKNOWN)) {
		tcpc->pd_wait_bc12_count = 1;
		tcpc_enable_timer(tcpc, TYPEC_RT_TIMER_PD_WAIT_BC12);
		mutex_unlock(&tcpc->access_lock);
		return ret;
	}
	tcpc->pd_wait_bc12_count = 0;
	tcpc_disable_timer(tcpc, TYPEC_RT_TIMER_PD_WAIT_BC12);
#endif /* CONFIG_USB_PD_WAIT_BC12 */

	ret = real_pd_put_cc_attached_event(tcpc, type);

	return ret;
}



/*----------------------------------------------------------------------------*/
static bool __pd_get_deferred_tcp_event(
	struct sgm41620_tcpc *tcpc, struct tcp_dpm_event *tcp_event)
{
	int index = 0;

	if (tcpc->tcp_event_count <= 0)
		return false;

	tcpc->tcp_event_count--;

	*tcp_event =
		tcpc->tcp_event_ring_buffer[tcpc->tcp_event_head_index];

	if (tcpc->tcp_event_count) {
		index = tcpc->tcp_event_head_index + 1;
		index %= TCP_EVENT_BUF_SIZE;
	}
	tcpc->tcp_event_head_index = index;
	return true;
}

bool pd_get_deferred_tcp_event(
	struct sgm41620_tcpc *tcpc, struct tcp_dpm_event *tcp_event)
{
	bool ret;

	ret = __pd_get_deferred_tcp_event(tcpc, tcp_event);
#if CONFIG_USB_PD_REV30
	if (tcpc->tcp_event_count)
		tcpc_restart_timer(tcpc, PD_TIMER_DEFERRED_EVT);
	else
		tcpc_disable_timer(tcpc, PD_TIMER_DEFERRED_EVT);
#endif	/* CONFIG_USB_PD_REV30 */

	return ret;
}

static bool __pd_put_deferred_tcp_event(
	struct sgm41620_tcpc *tcpc, const struct tcp_dpm_event *tcp_event)
{
	int index;

	index = (tcpc->tcp_event_head_index + tcpc->tcp_event_count);
	index %= TCP_EVENT_BUF_SIZE;

	tcpc->tcp_event_count++;
	tcpc->tcp_event_ring_buffer[index] = *tcp_event;

    tcpc_event_thread_wake_up(tcpc);
	return true;
}

bool pd_put_deferred_tcp_event(
	struct sgm41620_tcpc *tcpc, const struct tcp_dpm_event *tcp_event)
{
	bool ret = true;
	struct pd_port *pd_port = p_pd_port;

	if (!tcpc->pd_pe_running || tcpc->pd_wait_pe_idle) {
		log_i("pd_put_tcp_event failed0\n");
		ret = false;
		goto unlock_out;
	}

	if (tcpc->tcp_event_count >= TCP_EVENT_BUF_SIZE) {
		log_i("pd_put_tcp_event failed1\n");
		ret = false;
		goto unlock_out;
	}

	if (tcpc->pd_wait_hard_reset_complete) {
		log_i("pd_put_tcp_event failed2\n");
		ret = false;
		goto unlock_out;
	}

	switch (tcp_event->event_id) {
	case TCP_DPM_EVT_DISCOVER_CABLE_ID:
	case TCP_DPM_EVT_CABLE_SOFTRESET:
		dpm_reaction_set(pd_port,
			DPM_REACTION_DYNAMIC_VCONN |
			DPM_REACTION_VCONN_STABLE_DELAY);
		break;
	}

	ret = __pd_put_deferred_tcp_event(tcpc, tcp_event);
#if CONFIG_USB_PD_REV30
	if (ret)
		pd_port->pe_data.pd_traffic_idle = false;
	if (tcpc->tcp_event_count == 1)
		tcpc_enable_timer(tcpc, PD_TIMER_DEFERRED_EVT);
#endif	/* CONFIG_USB_PD_REV30 */

	dpm_reaction_set_ready_once(pd_port);

unlock_out:

	return ret;
}

void pd_notify_tcp_vdm_event_2nd_result(struct pd_port *pd_port, uint8_t ret)
{
#if CONFIG_USB_PD_TCPM_CB_2ND
	struct tcp_dpm_event *tcp_event = &pd_port->tcp_event;

	if (pd_port->tcp_event_id_2nd == TCP_DPM_EVT_UNKNOWN)
		return;

	if (pd_port->tcp_event_id_2nd < TCP_DPM_EVT_VDM_COMMAND ||
		pd_port->tcp_event_id_2nd >= TCP_DPM_EVT_IMMEDIATELY)
		return;

	if (tcp_event->event_cb != NULL)
		tcp_event->event_cb(p_tcpc_dev, ret, tcp_event);

	pd_port->tcp_event_id_2nd = TCP_DPM_EVT_UNKNOWN;
#endif	/* CONFIG_USB_PD_TCPM_CB_2ND */
}

void pd_notify_tcp_event_2nd_result(struct pd_port *pd_port, int ret)
{
#if CONFIG_USB_PD_TCPM_CB_2ND
	struct tcp_dpm_event *tcp_event = &pd_port->tcp_event;
	struct sgm41620_tcpc  *tcpc = p_tcpc_dev;

	if (pd_port->tcp_event_id_2nd == TCP_DPM_EVT_UNKNOWN)
		return;

	switch (ret) {
	case TCP_DPM_RET_DROP_SENT_SRESET:
		if (pd_port->tcp_event_id_2nd == TCP_DPM_EVT_SOFTRESET
			&& pd_port->tcp_event_drop_reset_once) {
			pd_port->tcp_event_drop_reset_once = false;
			return;
		}
		break;
	case TCP_DPM_RET_DROP_SENT_HRESET:
		if (pd_port->tcp_event_id_2nd == TCP_DPM_EVT_HARD_RESET
			&& pd_port->tcp_event_drop_reset_once) {
			pd_port->tcp_event_drop_reset_once = false;
			return;
		}
		break;
	case TCP_DPM_RET_SUCCESS:
		/* Ignore VDM */
		if (pd_port->tcp_event_id_2nd >= TCP_DPM_EVT_VDM_COMMAND
			&& pd_port->tcp_event_id_2nd < TCP_DPM_EVT_IMMEDIATELY)
			return;

		break;
	}

	log_i("tcp_event_2nd:evt%d=%d\n",
		pd_port->tcp_event_id_2nd, ret);

	if (tcp_event->event_cb != NULL)
		tcp_event->event_cb(tcpc, ret, tcp_event);

	pd_port->tcp_event_id_2nd = TCP_DPM_EVT_UNKNOWN;
#endif	/* CONFIG_USB_PD_TCPM_CB_2ND */
}

void pd_notify_tcp_event_1st_result(struct pd_port *pd_port, int ret)
{
	bool cb = true;
	struct tcp_dpm_event *tcp_event = &pd_port->tcp_event;
	struct sgm41620_tcpc  *tcpc = p_tcpc_dev;

	if (pd_port->tcp_event_id_1st == TCP_DPM_EVT_UNKNOWN)
		return;

	log_i("tcp_event_1st:evt%d=%d\n",
		pd_port->tcp_event_id_1st, ret);

#if CONFIG_USB_PD_TCPM_CB_2ND
	if (ret == TCP_DPM_RET_SENT) {
		cb = false;
		pd_port->tcp_event_id_2nd = tcp_event->event_id;
	}
#endif	/* CONFIG_USB_PD_TCPM_CB_2ND */

	if (cb && tcp_event->event_cb != NULL)
		tcp_event->event_cb(tcpc, ret, tcp_event);

	pd_port->tcp_event_id_1st = TCP_DPM_EVT_UNKNOWN;
}

static void __tcp_event_buf_reset(
	struct sgm41620_tcpc *tcpc, uint8_t reason)
{
	struct tcp_dpm_event tcp_event;

	pd_notify_tcp_event_2nd_result(p_pd_port, reason);

	while (__pd_get_deferred_tcp_event(tcpc, &tcp_event)) {
		if (tcp_event.event_cb != NULL)
			tcp_event.event_cb(tcpc, reason, &tcp_event);
	}
}

void pd_notify_tcp_event_buf_reset(struct pd_port *pd_port, uint8_t reason)
{
	struct sgm41620_tcpc *tcpc = p_tcpc_dev;

	pd_notify_tcp_event_1st_result(pd_port, reason);

	__tcp_event_buf_reset(tcpc, reason);

}

/*----------------------------------------------------------------------------*/

static void __pd_event_buf_reset(struct sgm41620_tcpc *tcpc, uint8_t reason)
{
	struct pd_event pd_event;

	tcpc->pd_hard_reset_event_pending = false;
	while (pd_get_event(tcpc, &pd_event))
		__pd_free_event(tcpc, &pd_event);

	if (tcpc->pd_pending_vdm_event) {
		__pd_free_event(tcpc, &tcpc->pd_vdm_event);
		tcpc->pd_pending_vdm_event = false;
	}

	tcpc->pd_pending_vdm_reset = false;
	tcpc->pd_pending_vdm_good_crc = false;
	tcpc->pd_pending_vdm_attention = false;

	__tcp_event_buf_reset(tcpc, reason);

}

void pd_event_buf_reset(struct sgm41620_tcpc *tcpc)
{
	log_i("pd_event_buf_reset\r\n");
	__pd_event_buf_reset(tcpc, TCP_DPM_RET_DROP_CC_DETACH);

}

void pd_put_recv_hard_reset_event(struct sgm41620_tcpc *tcpc)
{

	if (!tcpc->pd_pe_running)
		return;

	tcpci_notify_hard_reset_state(
		tcpc, TCP_HRESET_SIGNAL_RECV);

	tcpc->pd_transmit_state = PD_TX_STATE_HARD_RESET;

	if (!tcpc->pd_hard_reset_event_pending) {
		__pd_event_buf_reset(tcpc, TCP_DPM_RET_DROP_RECV_HRESET);
		__pd_put_hw_event(tcpc, PD_HW_RECV_HARD_RESET);
		tcpc->pd_bist_mode = PD_BIST_MODE_DISABLE;
		tcpc->pd_hard_reset_event_pending = true;
		tcpc->pd_ping_event_pending = false;

#if CONFIG_USB_PD_DIRECT_CHARGE
		tcpc->pd_during_direct_charge = false;
#endif	/* CONFIG_USB_PD_DIRECT_CHARGE */
	}

#if CONFIG_USB_PD_RETRY_CRC_DISCARD
	tcpc->pd_discard_pending = false;
#endif	/* CONFIG_USB_PD_RETRY_CRC_DISCARD */

}


void pd_put_sent_hard_reset_event(struct sgm41620_tcpc *tcpc)
{

	if (tcpc->pd_wait_hard_reset_complete){
		//log_i("pd_put_sent_hard_reset_event!!\n");
		__pd_event_buf_reset(tcpc, TCP_DPM_RET_DROP_SENT_HRESET);
	}
	else
		log_i("[HReset] Unattached\n");

	tcpc->pd_transmit_state = PD_TX_STATE_GOOD_CRC;
	__pd_put_pe_event(tcpc, PD_PE_HARD_RESET_COMPLETED);

}

void pd_put_cc_detached_event(struct sgm41620_tcpc *tcpc)
{
	//log_i("pd_put_cc_detached_event!!\r\n");
#if CONFIG_USB_PD_WAIT_BC12
	tcpc->pd_wait_bc12_count = 0;
	tcpc_disable_timer(tcpc, TYPEC_RT_TIMER_PD_WAIT_BC12);
#endif /* CONFIG_USB_PD_WAIT_BC12 */

	tcpci_notify_hard_reset_state(
		tcpc, TCP_HRESET_RESULT_FAIL);

	__pd_event_buf_reset(tcpc, TCP_DPM_RET_DROP_CC_DETACH);
	__pd_put_hw_event(tcpc, PD_HW_CC_DETACHED);

	tcpc->pd_wait_pe_idle = true;
	tcpc->pd_pe_running = false;
	tcpc->pd_wait_pr_swap_complete = false;
	tcpc->pd_hard_reset_event_pending = false;
	tcpc->pd_wait_vbus_once = PD_WAIT_VBUS_DISABLE;
	tcpc->pd_bist_mode = PD_BIST_MODE_DISABLE;
	tcpc->pd_ping_event_pending = false;

#if CONFIG_USB_PD_DIRECT_CHARGE
	tcpc->pd_during_direct_charge = false;
#endif	/* CONFIG_USB_PD_DIRECT_CHARGE */

#if CONFIG_USB_PD_RETRY_CRC_DISCARD
	tcpc->pd_discard_pending = false;
#endif	/* CONFIG_USB_PD_RETRY_CRC_DISCARD */

}




bool vdm_put_pe_event(struct sgm41620_tcpc *tcpc_dev, uint8_t pe_event)
{
	struct pd_event evt = {
		.event_type = PD_EVT_PE_MSG,
		.msg = pe_event,
		.pd_msg = NULL,
	};

	return pd_put_vdm_event(tcpc_dev, &evt, false);
}

bool vdm_put_dpm_discover_cable_id_event(struct pd_port *pd_port)
{
    /* waiting for dpm_ack event */
    return pd_put_tcp_vdm_event(pd_port, TCP_DPM_EVT_DISCOVER_CABLE_ID);
}

bool pd_put_vdm_event(struct sgm41620_tcpc *tcpc_dev,
        struct pd_event *pd_event, bool from_port_partner)
{
    bool ignore_evt = false;
    struct pd_msg *pd_msg = pd_event->pd_msg;

    if (from_port_partner && pd_is_init_attention_event(tcpc_dev, pd_event)) {
        log_i("AttEvt\r\n");
        ignore_evt = true;
        tcpc_dev->pd_pending_vdm_attention = true;
        tcpc_dev->pd_attention_vdm_msg = *pd_msg;
    }

    if (!ignore_evt && pd_event_ctrl_msg_match(pd_event, PD_CTRL_GOOD_CRC)) {
        log_d("GoodCRC\n");
        ignore_evt = true;
        tcpc_dev->pd_pending_vdm_good_crc = true;
    }

    if (ignore_evt) {
        tcpc_event_thread_wake_up(tcpc_dev);
    } else if (tcpc_dev->pd_pending_vdm_event) {
        /* If message from port partner, we have to overwrite it */
        /* If message from TCPM, we will reset_vdm later */
        ignore_evt = !from_port_partner;

        if (from_port_partner)
            __pd_free_event(tcpc_dev, &tcpc_dev->pd_vdm_event);
    }

    if (ignore_evt) {
        __pd_free_event(tcpc_dev, pd_event);
        goto out;
    }

    tcpc_dev->pd_vdm_event = *pd_event;
    tcpc_dev->pd_pending_vdm_event = true;
    tcpc_dev->pd_postpone_vdm_timeout = true;

    if (from_port_partner) {
        tcpc_dev->pd_last_vdm_msg = *pd_msg;
        pd_reset_pe_vdm_state(tcpc_dev, pd_msg->payload[0]);
        pd_postpone_vdm_event(tcpc_dev);
        goto out;
    }

    tcpc_event_thread_wake_up(tcpc_dev);
out:
    return !ignore_evt;
}

bool pd_put_pd_msg_event(struct sgm41620_tcpc *tcpc_dev, struct pd_msg *pd_msg)
{
	uint32_t cnt, cmd, extend;
#if CONFIG_USB_PD_RETRY_CRC_DISCARD
	bool discard_pending = false;
#endif	/* CONFIG_USB_PD_RETRY_CRC_DISCARD */
	struct pd_event evt = {
		.event_type = PD_EVT_PD_MSG,
		.pd_msg = pd_msg,
	};

	cnt = PD_HEADER_CNT(pd_msg->msg_hdr);
	cmd = PD_HEADER_TYPE(pd_msg->msg_hdr);
	extend = PD_HEADER_EXT(pd_msg->msg_hdr);

	/* bist mode */
	if (tcpc_dev->pd_bist_mode != PD_BIST_MODE_DISABLE) {
		__pd_free_event(tcpc_dev, &evt);
		return 0;
	}
	
#if CONFIG_USB_PD_RETRY_CRC_DISCARD
	if (tcpc_dev->pd_discard_pending && pd_msg->frame_type == TCPC_TX_SOP) {
		discard_pending = true;
		tcpc_dev->pd_discard_pending = false;

		if ((cmd == PD_CTRL_GOOD_CRC) && (cnt == 0)) {
			log_i("RETRANSMIT\n");
			__pd_free_event(tcpc_dev, &evt);
			tcpc_disable_timer(tcpc_dev, PD_TIMER_DISCARD);
			pd_put_hw_event(tcpc_dev, PD_HW_TX_RETRANSMIT);
			return 0;
		}
	}
#endif	/* CONFIG_USB_PD_RETRY_CRC_DISCARD */

#if CONFIG_USB_PD_DROP_REPEAT_PING
	if (cnt == 0 && cmd == PD_CTRL_PING) {
		/* reset ping_test_mode only if cc_detached */
		if (!tcpc_dev->pd_ping_event_pending) {
			log_i("ping_test_mode\n");
			tcpc_dev->pd_ping_event_pending = true;
			tcpci_set_bist_test_mode(tcpc_dev, true);
		} else {
			__pd_free_event(tcpc_dev, &evt);
			return 0;
		}
	}
#endif	/* CONFIG_USB_PD_DROP_REPEAT_PING */
	if (cnt != 0 && cmd == PD_DATA_BIST && extend == 0)
		tcpc_dev->pd_bist_mode = PD_BIST_MODE_EVENT_PENDING;
	
	
	
#if CONFIG_USB_PD_RETRY_CRC_DISCARD
	if (discard_pending) {
		tcpc_disable_timer(tcpc_dev, PD_TIMER_DISCARD);
		pd_put_hw_event(tcpc_dev, PD_HW_TX_DISCARD);
	}
#endif	/* CONFIG_USB_PD_RETRY_CRC_DISCARD */
	
    if (cnt != 0 && cmd == PD_DATA_VENDOR_DEF && extend == 0){
		//log_i("[%s] : cnt = %d,cmd = %d\r\n",__func__,cnt,cmd);
		return pd_put_vdm_event(tcpc_dev, &evt,true);
	}

    if (!pd_put_event(tcpc_dev, &evt, true)) {
        __pd_free_event(tcpc_dev, &evt);
        return false;
    }

    return true;
}



bool vdm_put_hw_event(struct sgm41620_tcpc *tcpc_dev, uint8_t hw_event)
{
	struct pd_event evt = {
		.event_type = PD_EVT_HW_MSG,
		.msg = hw_event,
		.pd_msg = NULL,
	};

	return pd_put_vdm_event(tcpc_dev, &evt,false);
}

bool pd_put_hw_event(struct sgm41620_tcpc *tcpc_dev, uint8_t hw_event)
{
	struct pd_event evt = {
		.event_type = PD_EVT_HW_MSG,
		.msg = hw_event,
		.pd_msg = NULL,
	};
	//log_i("fuc: %s\r\n",__func__);
	return pd_put_event(tcpc_dev, &evt, false);
}


void pd_try_put_pe_idle_event(struct pd_port *pd_port)
{

	if (p_tcpc_dev->pd_transmit_state < PD_TX_STATE_WAIT){
		//log_i("%s : put event ==> PD_PE_IDLE\r\n",__func__);
		__pd_put_pe_event(p_tcpc_dev, PD_PE_IDLE);
	}
}

bool pd_check_ctrl_msg_event(struct pd_port *pd_port, uint8_t msg)
{
	return pd_event_ctrl_msg_match(
		pd_get_curr_pd_event(pd_port), msg);
}

void pd_notify_pe_idle(struct pd_port *pd_port)
{
	//log_i("pd_notify_pe_idle\r\n");
	bool notify_pe_idle = false;
	struct sgm41620_tcpc *tcpc_dev = p_tcpc_dev;
    
	if (tcpc_dev->pd_wait_pe_idle) {
		notify_pe_idle = true;
		tcpc_dev->pd_wait_pe_idle = false;
	}

    tcpc_dev->pd_pe_running = false;

	pd_update_connect_state(pd_port, PD_CONNECT_NONE);

	if (notify_pe_idle){
		//tcpc_enable_timer(tcpc_dev, TYPEC_RT_TIMER_PE_IDLE);
		log_i("typec_handle_pe_idle\r\n");
		typec_handle_pe_idle(tcpc_dev);
	}
}


void pd_put_vbus_changed_event(struct sgm41620_tcpc *tcpc)
{

	int vbus_valid;
/*#if CONFIG_USB_PD_SAFE5V_DELAY
	tcpc_disable_timer(tcpc, PD_TIMER_VSAFE5V_DELAY);
#endif*/
	//log_i("pd_put_vbus_changed_event\n");
	vbus_valid = tcpci_check_vbus_valid(tcpc);
#if 1
	switch (tcpc->pd_wait_vbus_once) {
	case PD_WAIT_VBUS_VALID_ONCE:
		if (vbus_valid) {
			//log_i("PD_WAIT_VBUS_VALID_ONCE\n");
			tcpc->pd_wait_vbus_once = PD_WAIT_VBUS_DISABLE;
			__pd_put_hw_event(tcpc, PD_HW_VBUS_PRESENT);
		}
		break;

	case PD_WAIT_VBUS_INVALID_ONCE:
		if (!vbus_valid) {
			tcpc->pd_wait_vbus_once = PD_WAIT_VBUS_DISABLE;
			__pd_put_hw_event(tcpc, PD_HW_VBUS_ABSENT);
		}
		break;
	default:
		break;
	}
#endif
}

void pd_put_vbus_safe0v_event(struct sgm41620_tcpc *tcpc, bool safe0v)
{
#if CONFIG_USB_PD_SAFE0V_DELAY
	tcpc_disable_timer(tcpc, PD_TIMER_VSAFE0V_DELAY);
#endif	/* CONFIG_USB_PD_SAFE0V_DELAY */
#if CONFIG_USB_PD_SAFE0V_TIMEOUT
	tcpc_disable_timer(tcpc, PD_TIMER_VSAFE0V_TOUT);
#endif	/* CONFIG_USB_PD_SAFE0V_TIMEOUT */

#if CONFIG_USB_PD_SAFE0V_TIMEOUT
	tcpci_enable_force_discharge(tcpc, false, 0);
#endif	/* CONFIG_USB_PD_SAFE0V_TIMEOUT */
	if (tcpc->pd_wait_vbus_once == PD_WAIT_VBUS_SAFE0V_ONCE && safe0v) {
		tcpc->pd_wait_vbus_once = PD_WAIT_VBUS_DISABLE;
		__pd_put_hw_event(tcpc, PD_HW_VBUS_SAFE0V);
	}
}

void pd_put_vbus_stable_event(struct sgm41620_tcpc *tcpc)
{
	if (tcpc->pd_wait_vbus_once == PD_WAIT_VBUS_STABLE_ONCE) {
		tcpc->pd_wait_vbus_once = PD_WAIT_VBUS_DISABLE;
#if CONFIG_USB_PD_SRC_HIGHCAP_POWER
		tcpci_enable_force_discharge(tcpc, false, 0);
#endif	/* CONFIG_USB_PD_SRC_HIGHCAP_POWER */
		__pd_put_hw_event(tcpc, PD_HW_VBUS_STABLE);
	}
}


void pd_notify_pe_wait_vbus_once(struct pd_port *pd_port, int wait_evt)
{
	bool as_sink = tcpc_typec_is_act_as_sink_role(p_tcpc_dev);
	
	p_tcpc_dev->pd_wait_vbus_once = wait_evt;

	switch (wait_evt) {
	case PD_WAIT_VBUS_VALID_ONCE:
	case PD_WAIT_VBUS_INVALID_ONCE:
		//log_i("pd_notify_pe_wait_vbus_once\r\n");
		pd_put_vbus_changed_event(p_tcpc_dev);
		break;

	case PD_WAIT_VBUS_SAFE0V_ONCE:
		if (tcpci_check_vsafe0v(p_tcpc_dev)) {
			log_i("case PD_WAIT_VBUS_SAFE0V_ONCE\r\n");
			pd_put_vbus_safe0v_event(p_tcpc_dev, true);
			break;
		}

#if CONFIG_USB_PD_SAFE0V_TIMEOUT
		if (!as_sink) {
			tcpci_enable_force_discharge(p_tcpc_dev, true, 0);
		}
		tcpc_enable_timer(p_tcpc_dev, PD_TIMER_VSAFE0V_TOUT);
#endif	/* CONFIG_USB_PD_SAFE0V_TIMEOUT */

		break;
	}
}

void pd_notify_pe_hard_reset_completed(struct pd_port *pd_port)
{
	tcpci_notify_hard_reset_state(
		p_tcpc_dev, TCP_HRESET_RESULT_DONE);
}
void pd_notify_pe_error_recovery(struct pd_port *pd_port)
{
	tcpci_notify_hard_reset_state(
		p_tcpc_dev, TCP_HRESET_RESULT_FAIL);

	p_tcpc_dev->pd_wait_pr_swap_complete = false;
	__tcp_event_buf_reset(p_tcpc_dev, TCP_DPM_RET_DROP_ERROR_REOCVERY);

	tcpc_typec_error_recovery(p_tcpc_dev);
}

void pd_notify_pe_send_hard_reset(struct pd_port *pd_port)
{

	p_tcpc_dev->pd_transmit_state = PD_TX_STATE_WAIT_HARD_RESET;
	tcpci_notify_hard_reset_state(p_tcpc_dev, TCP_HRESET_SIGNAL_SEND);
}


bool pd_is_pe_wait_pd_transmit_done(struct pd_port *pd_port)
{
	bool tx_wait;
	struct sgm41620_tcpc *tcpc = p_tcpc_dev;

	tx_wait = tcpc->pd_transmit_state == PD_TX_STATE_WAIT_CRC_PD;

	return tx_wait;
}

void pd_notify_pe_transmit_msg(
	struct pd_port *pd_port, uint8_t type)
{
	struct sgm41620_tcpc *tcpc = p_tcpc_dev;

	tcpc->pd_transmit_state = type;
}


void pd_notify_pe_execute_pr_swap(struct pd_port *pd_port)
{
	
	struct sgm41620_tcpc *tcpc = p_tcpc_dev;

	tcpc->pd_wait_pr_swap_complete = true;
	//log_i("pd_wait_pr_swap_complete = %d\r\n",p_tcpc_dev->pd_wait_pr_swap_complete);
}

void pd_notify_pe_reset_protocol(struct pd_port *pd_port)
{
	struct sgm41620_tcpc *tcpc = p_tcpc_dev;

	if (!tcpc->pd_wait_pr_swap_complete)
		return;

	tcpc->pd_wait_pr_swap_complete = false;

	/*
	 *	CC_Alert was ignored if pd_wait_pr_swap_complete = true
	 *	So enable PDDebounce to detect CC_Again.
	 */

	tcpc_enable_timer(tcpc, TYPEC_TIMER_PDDEBOUNCE);
}

void pd_notify_pe_cancel_pr_swap(struct pd_port *pd_port)
{
	struct sgm41620_tcpc *tcpc = p_tcpc_dev;
	//log_i("pd_wait_pr_swap_complete = %d\r\n",tcpc->pd_wait_pr_swap_complete);
	if (!tcpc->pd_wait_pr_swap_complete){
		return;
	}
	pd_port->pe_data.during_swap = false;
	pd_notify_pe_reset_protocol(pd_port);

	if (!tcpci_check_vbus_valid(tcpc)
		&& (pd_port->request_v >= 4000)) {
		log_i("cancel_pr_swap_vbus=0\n");
		pd_put_tcp_pd_event(pd_port, TCP_DPM_EVT_ERROR_RECOVERY,
				    PD_TCP_FROM_PE);
	}
}


void pd_notify_pe_pr_changed(struct pd_port *pd_port)
{
	//struct sgm41620_tcpc *tcpc = p_tcpc_dev;

	tcpc_typec_handle_pe_pr_swap(p_tcpc_dev);
}

void pd_notify_pe_snk_explicit_contract(struct pd_port *pd_port)
{
#if CONFIG_USB_PD_REV30
	struct pe_data *pe_data = &pd_port->pe_data;
	struct sgm41620_tcpc *tcpc = p_tcpc_dev;

	if (pe_data->explicit_contract || !pd_check_rev30(pd_port)){
		log_i("pd_notify_pe_snk_explicit_contract\r\n");
		return;
	}
	if (tcpc->typec_remote_rp_level == TYPEC_CC_VOLT_SNK_3_0){
		log_i("PD_SINK_TX_OK\r\n");
		pe_data->pd_traffic_control = PD_SINK_TX_OK;
	}
	else{
		log_i("PD_SINK_TX_NG\r\n");
		pe_data->pd_traffic_control = PD_SINK_TX_NG;
	}

#if CONFIG_USB_PD_REV30_SNK_FLOW_DELAY_STARTUP
	if (pe_data->pd_traffic_control == PD_SINK_TX_OK) {
		pe_data->pd_traffic_control = PD_SINK_TX_START;
		pd_restart_timer(pd_port, PD_TIMER_SNK_FLOW_DELAY);
	}
#endif	/* CONFIG_USB_PD_REV30_SNK_FLOW_DELAY_STARTUP */
#endif	/* CONFIG_USB_PD_REV30 */
}

void pd_notify_pe_src_explicit_contract(struct pd_port *pd_port)
{
	uint8_t pull = TYPEC_CC_RP_3_0;
	struct pe_data *pe_data = &pd_port->pe_data;
	struct sgm41620_tcpc *tcpc = p_tcpc_dev;

	if (pe_data->explicit_contract) {
#if CONFIG_USB_PD_REV30_SRC_FLOW_DELAY_STARTUP
		if (pd_check_rev30(pd_port) &&
			(pe_data->pd_traffic_control == PD_SOURCE_TX_START))
			pd_restart_timer(pd_port, PD_TIMER_SINK_TX);
#endif	/* CONFIG_USB_PD_REV30_SRC_FLOW_DELAY_STARTUP */
		return;
	}

#if CONFIG_USB_PD_REV30
	if (pd_check_rev30(pd_port)) {
#if CONFIG_USB_PD_REV30_SRC_FLOW_DELAY_STARTUP
		pe_data->pd_traffic_control = PD_SOURCE_TX_START;
		pd_enable_timer(pd_port, PD_TIMER_SINK_TX);
#else
		pe_data->pd_traffic_control = PD_SINK_TX_OK;
#endif	/* CONFIG_USB_PD_REV30_SRC_FLOW_DELAY_STARTUP */
	}
#endif	/* CONFIG_USB_PD_REV30 */

	if (pull) {
		tcpci_set_cc(tcpc, pull);
	}
}

void tcpc_event_thread(void)
{
    static uint8_t weight;

    if (p_tcpc_dev->event_loop_thread_stop)
        return;

    if (p_tcpc_dev->pending_event) {
        weight = 0;
        do {
            // Yield cpu to handle alert event with higher priority.
            // It requires at least 2 rounds for the case that SRC DPM
            // has handled ACK/NAK event and need to set SinkTxOk as
            // soon as possible through dpm_reactions.
            if (++weight > 2) {
                weight = 0;
                goto out;
            }

            // Maybe fake pending_event increases in the case of
            // wrong usage of tcpc_event_thread_wake_up, so decrease
            // pending_event whether pd_policy_engine_run() returns 
            // true or false.
            DEC_IF_POSITIVE(p_tcpc_dev->pending_event);
        } while(pd_policy_engine_run());
        p_tcpc_dev->event_loop_thread_stop = true;
    }

out:
    return;
}

void tcpc_event_thread_wake_up(struct sgm41620_tcpc *tcpc_dev)
{
    p_tcpc_dev->pending_event++;
    p_tcpc_dev->event_loop_thread_stop = false;
}

int tcpci_event_init_work(struct sgm41620_tcpc *tcpc_dev)
{
    p_tcpc_dev->event_loop_thread_stop = true;
    p_tcpc_dev->pending_event = 0;

    p_tcpc_dev->pd_inited_flag = 1;

    if (p_tcpc_dev->typec_attach_new)
        pd_put_cc_attached_event(p_tcpc_dev, p_tcpc_dev->typec_attach_new);

    return 0;
}

int tcpci_event_deinit(struct sgm41620_tcpc *tcpc_dev)
{
	p_tcpc_dev->event_loop_thread_stop = true;
	return 0;
}
